﻿namespace PerformanceTestWrapper
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using System.Threading;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    /// <summary>
    /// This class is used to perform all defined tests in the GuiaTest Project. 
    /// This is necessary for profiling issues, due the profiler is not able to profile a testproject directly.
    /// </summary>
    public class PerformanceTestExecutor
    {
        /// <summary>
        /// The name of the compiled assembly of the tests.
        /// </summary>
        private const string TestAssemblyName = "GuiaTest.dll";
        
        /// <summary>
        /// Starts the tests.
        /// </summary>
        /// <param name="args">Needed arguments.</param>
        public static void Main(string[] args)
        {
            PerformanceTestExecutor.ExecuteFromDLL();
        }

        /// <summary>
        /// Executes all tests in the given DLL file.
        /// </summary>
        private static void ExecuteFromDLL()
        {
            Assembly assembly = Assembly.LoadFile(Directory.GetCurrentDirectory() + "\\" + TestAssemblyName);
            Type[] types = assembly.GetTypes();
            foreach (Type t in types)
            {
                if (t.IsAbstract)
                {
                    continue;
                }

                if (Attribute.IsDefined(t, typeof(TestClassAttribute)))
                {
                    ConstructorInfo testConstructor = t.GetConstructor(new Type[] { });
                    object obj = testConstructor.Invoke(new object[] { });
                    MethodInfo[] methods = t.GetMethods();
                    MethodInfo initMethod = null;
                    MethodInfo cleanupMethod = null;
                    List<MethodInfo> testMethods = new List<MethodInfo>();
                    foreach (MethodInfo method in methods)
                    {
                        if (Attribute.IsDefined(method, typeof(TestInitializeAttribute)))
                        {
                            initMethod = method;
                        }
                        if (Attribute.IsDefined(method, typeof(TestCleanupAttribute)))
                        {
                            cleanupMethod = method;
                        }
                        if (Attribute.IsDefined(method, typeof(TestMethodAttribute)) && !Attribute.IsDefined(method, typeof(IgnoreAttribute)))
                        {
                            testMethods.Add(method);
                        }
                    }

                    // Run tests
                    Console.WriteLine("TEST: " + t.ToString());
                    foreach (MethodInfo testMethod in testMethods)
                    {
                        Console.WriteLine("- " + testMethod.ToString());
                        try
                        {
                            if (initMethod != null)
                            {
                                initMethod.Invoke(obj, new object[] { });
                            }
                        }
                        catch (Exception)
                        {
                            // this is probably an expected exception
                        }

                        try
                        {
                            testMethod.Invoke(obj, new object[] { });
                        }
                        catch (Exception)
                        {
                            // this is probably an expected exception
                        }

                        try
                        {
                            if (cleanupMethod != null)
                            {
                                cleanupMethod.Invoke(obj, new object[] { });
                            }
                        }
                        catch (Exception)
                        {
                            // this is probably an expected exception
                        }
                    }

                    Thread.Sleep(400);
                }
            }

            Console.WriteLine("==================");
            Console.WriteLine("ALL TESTS EXECUTED");
            Console.ReadKey();
        }
    }
}
